<?php
/**
 * Created by PhpStorm.
 * User: yuliang
 * Date: 2017/5/29
 * Time: 下午3:02
 */

namespace app\behavior;

use think\Config;
use app\common;
use think\Cookie;

class TokenAuth
{
    /**
     * 加密串
     */
    private $secretKey = '@6xNVxqn72ym!=YBbUw';
    /**
     * token有效期
     */
    private $tokenLifetime =  '1209600';

    /**
     * 存储解析后的access token的相关信息
     */
    private $session = [];

    public function __construct()
    {
        $this->secretKey = common\Config::$tokenSecretKey;
    }

    public function run()
    {
        $whiteList = Config::get('api_white_list');
        $urlPath = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);

        //白名单中的接口不需要校验 token
        if (is_array($whiteList) && in_array($urlPath, $whiteList)) {
            return true;
        }

        if (!input('?token')) {
//             throw new common\ApiException(common\ApiErrorDescs::EC_INVALID_TOKEN);
        }
        $token = input('token');

        $result = $this->checkToken($token);
        if (!$result) {
//             throw new common\ApiException(common\ApiErrorDescs::EC_INVALID_TOKEN);
        }

        //校验user 已封号账号拒绝请求
        if( !$this->checkUser()) {
            throw new common\ApiException(common\ApiErrorDescs::EC_UNKNOWN_USER);
        }

        $this->setUserCookie();

        return $result;
    }

    /**
     * 校验token
     * @var TokenAuth
     * @param string $token token字符串
     * @return bool
     */
    public function checkToken($token) {
        //解析token
        $this->session = $this->_parseSessionKey($token);
//dump($this->session);
        //判断是否过期
        if ($this->session['expire_time'] - time() <= 0) {
            return false;
        }

        //校验token归属
        $uid = input('uid', 0);
//        if ($this->session['uid'] != $uid) {
//            return false;
//        }

        $sign = $this->generateTokenSign(
            $this->session['timestamp'],
            $this->session['uid'],
            $this->session['app_id'],
            $this->secretKey
        );

        if ($this->session['sign'] != $sign) {
            return false;
        }

        $this->session['token'] = $token;

        return true;
    }

    /**
     * 生成access token
     * @param int $uid 用户ID
     * @param int $appid 应用ID
     * @param int $type token类型
     * @return string $token
     */
    public function generateToken($uid, $appid, $type=11) {
        $time = time();
        //生成签名串
        $sign = $this->generateTokenSign($time, $uid, $appid, $this->secretKey);

        $tokenData = [$type, $sign, $time, $uid];
        $token = implode('.', $tokenData) . '-' . $appid;

        return $token;
    }

    /**
     * 解析服务器端 token
     * @param string $token
     * @return array(参数数组，格式详见函数最后)|false
     */
    private function _parseSessionKey($token) {
        list($tmp,$appid) = explode('-',$token);
        list($type,$sign,$timestamp,$uid) = explode('.',$tmp);
        return [
            'uid'         => intval($uid),
            'app_id'      => intval($appid),
            'token_type'  => intval($type),
            'sign'        => $sign,
            'timestamp'   => intval($timestamp),
            'expires'     => $this->tokenLifetime,  //有效期
            'expire_time' => intval($timestamp) + $this->tokenLifetime, // 过期时间
        ];
    }

    /**
     * 产生令牌签名
     * @param int $timestamp token的时间戳
     * @param int $uid token中包含的，不关心其有效与否
     * @param int $appid 应用id
     * @param string $sk app的secret_key
     * @return string
     */
    private function generateTokenSign($timestamp, $uid, $appid, $sk) {
        $str = $timestamp . $uid . $appid . $sk;
        return md5($str);
    }

    /**
     * 获取应用和用户的相关信息
     * @return array
     */
    public function getSession() {
        return $this->session;
    }

    /**
     * 获取session中的某个值
     * @param $key 键名
     * @return string
     */
    public function getSessionByKey($key) {
        return isset($this->session[$key]) ? $this->session[$key]: '';
    }

    /**
     * 校验是否有效用户
     * @return boolean
     */
    private function checkUser() {
        $uid = $this->session['uid'];

        $userDao = new common\dao\User();
        $user = $userDao->getUserByUid($uid);

        if (empty($user) || $user['status'] == common\dao\User::USER_STATUS_CLOSE) {
            return false;
        }

        //
        $cookieUser = array(
            'uid' => $user['uid'],
            'mobile' => $user['mobile'],
            'nickname' => $user['nickname'],
            'gender' => $user['gender'],
            'is_vip' => $user['is_vip'],
            'account_type' => $user['account_type'],
            'vip_level' => $user['vip_level'],
        );
        $this->session['user'] = $cookieUser;
        return true;
    }
    /**
     * 设置用户cookie信息
     */
    private function setUserCookie() {
        Cookie::set('user', $this->session['user']);
    }
}
